using System;
using System.Globalization;
using System.Runtime.InteropServices;
using PickGold.Charting;

namespace PickGold.Charting.Formulas
{
	internal class Oscillators : PriceIndicators
	{
		private void ChaikinOscillator(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num;
			int num2;
			double[] numArray2;
			double[] numArray3;
			if (inputValues.Length != 5)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresFourArrays);
			}
			base.CheckNumOfValues(inputValues, 4);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 3;
			}
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = 10;
			}
			if (((num > num2) || (num2 <= 0)) || (num <= 0))
			{
				throw new ArgumentException(SR.ExceptionOscillatorObjectInvalidPeriod);
			}
			bool startFromFirst = bool.Parse(extraParameterList[0]);
			VolumeIndicators indicators = new VolumeIndicators();
			double[][] numArray = new double[2][];
			indicators.AccumulationDistribution(inputValues, out numArray);
			base.ExponentialMovingAverage(numArray[1], out numArray2, num2, startFromFirst);
			base.ExponentialMovingAverage(numArray[1], out numArray3, num, startFromFirst);
			outputValues = new double[2][];
			int num3 = Math.Min(numArray3.Length, numArray2.Length);
			outputValues[0] = new double[num3];
			outputValues[1] = new double[num3];
			int index = 0;
			for (int i = inputValues[1].Length - num3; i < inputValues[1].Length; i++)
			{
				outputValues[0][index] = inputValues[0][i];
				if (startFromFirst)
				{
					outputValues[1][index] = numArray3[index] - numArray2[index];
				}
				else if (((index + num2) - num) < numArray3.Length)
				{
					outputValues[1][index] = numArray3[(index + num2) - num] - numArray2[index];
				}
				else
				{
					outputValues[1][index] = double.NaN;
				}
				index++;
			}
		}

		private void DetrendedPriceOscillator(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			double[] numArray;
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			try
			{
				num = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			base.MovingAverage(inputValues[1], out numArray, num, false);
			outputValues = new double[][] { new double[inputValues[0].Length - ((num * 3) / 2)], new double[inputValues[1].Length - ((num * 3) / 2)] };
			for (int i = 0; i < outputValues[1].Length; i++)
			{
				outputValues[0][i] = inputValues[0][(i + num) + (num / 2)];
				outputValues[1][i] = inputValues[1][(i + num) + (num / 2)] - numArray[i];
			}
		}

		public override void Formula(string formulaName, double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList, out string[][] outLabels)
		{
			outputValues = null;
			outLabels = null;
			string name = formulaName.ToUpper(CultureInfo.InvariantCulture);
			try
			{
				switch (name)
				{
					case "STOCHASTICINDICATOR":
						this.StochasticIndicator(inputValues, out outputValues, parameterList);
						return;

					case "CHAIKINOSCILLATOR":
						this.ChaikinOscillator(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "DETRENDEDPRICEOSCILLATOR":
						this.DetrendedPriceOscillator(inputValues, out outputValues, parameterList);
						return;

					case "VOLATILITYCHAIKINS":
						this.VolatilityChaikins(inputValues, out outputValues, parameterList);
						return;

					case "VOLUMEOSCILLATOR":
						this.VolumeOscillator(inputValues, out outputValues, parameterList);
						return;

					case "WILLIAMSR":
						this.WilliamsR(inputValues, out outputValues, parameterList);
						return;
				}
				outputValues = null;
			}
			catch (IndexOutOfRangeException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaInvalidPeriod(name));
			}
			catch (OverflowException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaNotEnoughDataPoints(name));
			}
		}

		internal void StochasticIndicator(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			int num2;
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			base.CheckNumOfValues(inputValues, 3);
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 10;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = 10;
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			outputValues = new double[][] { new double[((inputValues[0].Length - num2) - num) + 2], new double[((inputValues[0].Length - num2) - num) + 2], new double[((inputValues[0].Length - num2) - num) + 2] };
			double[] numArray = new double[(inputValues[0].Length - num2) + 1];
			for (int i = num2 - 1; i < inputValues[0].Length; i++)
			{
				double maxValue = double.MaxValue;
				double minValue = double.MinValue;
				for (int j = (i - num2) + 1; j <= i; j++)
				{
					if (maxValue > inputValues[2][j])
					{
						maxValue = inputValues[2][j];
					}
					if (minValue < inputValues[1][j])
					{
						minValue = inputValues[1][j];
					}
				}
				numArray[(i - num2) + 1] = ((inputValues[3][i] - maxValue) / (minValue - maxValue)) * 100.0;
				if (i >= ((num2 + num) - 2))
				{
					outputValues[0][((i - num2) - num) + 2] = inputValues[0][i];
					outputValues[1][((i - num2) - num) + 2] = numArray[(i - num2) + 1];
				}
			}
			base.MovingAverage(numArray, out outputValues[2], num, false);
		}

		private void VolatilityChaikins(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			int num2;
			double[] numArray;
			if (inputValues.Length != 3)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
			}
			base.CheckNumOfValues(inputValues, 2);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 10;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionOscillatorNegativePeriodParameter);
			}
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = 10;
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionOscillatorNegativeSignalPeriod);
			}
			double[] numArray2 = new double[inputValues[1].Length];
			for (int i = 0; i < inputValues[1].Length; i++)
			{
				numArray2[i] = inputValues[1][i] - inputValues[2][i];
			}
			base.ExponentialMovingAverage(numArray2, out numArray, num2, false);
			outputValues = new double[][] { new double[numArray.Length - num], new double[numArray.Length - num] };
			for (int j = 0; j < outputValues[1].Length; j++)
			{
				outputValues[0][j] = inputValues[0][((j + num) + num2) - 1];
				if (numArray[j] != 0.0)
				{
					outputValues[1][j] = ((numArray[j + num] - numArray[j]) / numArray[j]) * 100.0;
				}
				else
				{
					outputValues[1][j] = 0.0;
				}
			}
		}

		private void VolumeOscillator(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			int num2;
			bool flag;
			double[] numArray;
			double[] numArray2;
			if (inputValues.Length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			base.CheckNumOfValues(inputValues, 1);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 5;
			}
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = 10;
			}
			if (((num > num2) || (num2 <= 0)) || (num <= 0))
			{
				throw new ArgumentException(SR.ExceptionOscillatorObjectInvalidPeriod);
			}
			if ((parameterList.Length < 3) || !bool.TryParse(parameterList[2], out flag))
			{
				flag = true;
			}
			base.MovingAverage(inputValues[1], out numArray, num, false);
			base.MovingAverage(inputValues[1], out numArray2, num2, false);
			outputValues = new double[][] { new double[numArray2.Length], new double[numArray2.Length] };
			for (int i = 0; i < numArray2.Length; i++)
			{
				outputValues[0][i] = inputValues[0][(i + num2) - 1];
				outputValues[1][i] = numArray[i + num] - numArray2[i];
				if (flag)
				{
					if (numArray2[i] == 0.0)
					{
						outputValues[1][i] = 0.0;
					}
					else
					{
						outputValues[1][i] = (outputValues[1][i] / numArray[i + num]) * 100.0;
					}
				}
			}
		}

		internal void WilliamsR(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			base.CheckNumOfValues(inputValues, 3);
			if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 14;
			}
			if (num <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			outputValues = new double[][] { new double[(inputValues[0].Length - num) + 1], new double[(inputValues[0].Length - num) + 1] };
			for (int i = num - 1; i < inputValues[0].Length; i++)
			{
				double maxValue = double.MaxValue;
				double minValue = double.MinValue;
				for (int j = (i - num) + 1; j <= i; j++)
				{
					if (maxValue > inputValues[2][j])
					{
						maxValue = inputValues[2][j];
					}
					if (minValue < inputValues[1][j])
					{
						minValue = inputValues[1][j];
					}
				}
				outputValues[0][(i - num) + 1] = inputValues[0][i];
				outputValues[1][(i - num) + 1] = ((minValue - inputValues[3][i]) / (minValue - maxValue)) * -100.0;
			}
		}

		public override string Name
		{
			get
			{
				return "Oscillators";
			}
		}
	}
}

